package com.linsen.erp.admin.listener;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.linsen.erp.admin.entity.ErrorLogEntity;
import com.linsen.erp.admin.entity.LoginLogEntity;
import com.linsen.erp.admin.entity.OperationLogEntity;
import com.linsen.erp.admin.service.IErrorLogService;
import com.linsen.erp.admin.service.ILoginLogService;
import com.linsen.erp.admin.service.IOperationLogService;
import com.linsen.core.common.enums.ModuleService;
import com.linsen.core.common.util.BrowserUtils;
import com.linsen.core.common.util.OsUtils;
import com.linsen.core.log.area.IPUtils;
import com.linsen.core.log.area.IpArea;
import com.linsen.core.log.enums.LogType;
import com.linsen.core.log.enums.LoginType;
import com.linsen.core.log.model.Log;
import com.linsen.core.rabbitmq.constant.QueueConstant;
import com.rabbitmq.client.Channel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.time.LocalDateTime;

/**
 * @author zhaoyong
 * @date 2023/3/14
 */
@Slf4j
@Component
@RequiredArgsConstructor
@RabbitListener(queues = QueueConstant.SYSTEM_LOG_DIRECT_QUEUE)
public class LogQueueListener {

    private final ILoginLogService iLoginLogService;
    private final IOperationLogService iOperationLogService;
    private final IErrorLogService iErrorLogService;

    @RabbitHandler
    public void handler(@Payload Log parsedLog, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel) {
        try {
            LogType logType = parsedLog.getLogType();
            LoginType loginType = parsedLog.getLoginType();
            String traceId = parsedLog.getTraceId();
            ModuleService moduleService = parsedLog.getModuleService();
            String title = parsedLog.getTitle();
            String operation = parsedLog.getOperation();
            String method = parsedLog.getMethod();
            String url = parsedLog.getUrl();
            String params = parsedLog.getParams();
            String ip = parsedLog.getIp();
            Long executeTime = parsedLog.getExecuteTime();
            String exception = parsedLog.getException();
            String userAgent = parsedLog.getUserAgent();
            String createBy = parsedLog.getCreateBy();
            String createByName = parsedLog.getCreateByName();
            LocalDateTime createTime = parsedLog.getCreateTime();

            //解析ip
            String location = null;
            String isp = null;
            if (ObjectUtil.isNotEmpty(ip)) {
                IpArea ipArea = IPUtils.getAreaId(ip);
                if (ObjectUtil.isNotNull(ipArea)) {
                    location = JSONObject.toJSONString(ipArea);
                    isp = ipArea.getIsp();
                }
            }

            //解析userAgent
            String os = null;
            String browser = null;
            if (ObjectUtil.isNotEmpty(userAgent)) {
                os = OsUtils.getOsType(userAgent).getDescription();
                browser = BrowserUtils.getBrowserType(userAgent).value();
            }

            switch (logType) {
                case LOGIN: {
                    LoginLogEntity loginLogEntity = new LoginLogEntity();
                    loginLogEntity.setType(loginType.getValue());
                    loginLogEntity.setTraceId(traceId);
                    loginLogEntity.setIp(ip);
                    loginLogEntity.setLocation(location);
                    loginLogEntity.setIsp(isp);
                    loginLogEntity.setUserAgent(userAgent);
                    loginLogEntity.setOs(os);
                    loginLogEntity.setBrowser(browser);
                    loginLogEntity.setCreateBy(createBy);
                    loginLogEntity.setCreateByName(createByName);
                    loginLogEntity.setCreateTime(createTime);
                    iLoginLogService.save(loginLogEntity);
                }
                break;
                case OPERATION: {
                    OperationLogEntity operationLogEntity = new OperationLogEntity();
                    operationLogEntity.setTraceId(traceId);
                    operationLogEntity.setModule(moduleService.getDescription());
                    operationLogEntity.setContent(title);
                    operationLogEntity.setMethod(method);
                    operationLogEntity.setUrl(url);
                    operationLogEntity.setRequestParam(params);
                    operationLogEntity.setResponseParam(operation);
                    operationLogEntity.setExecuteTime(executeTime);
                    operationLogEntity.setIp(ip);
                    operationLogEntity.setLocation(location);
                    operationLogEntity.setIsp(isp);
                    operationLogEntity.setUserAgent(userAgent);
                    operationLogEntity.setOs(os);
                    operationLogEntity.setBrowser(browser);
                    operationLogEntity.setCreateBy(createBy);
                    operationLogEntity.setCreateByName(createByName);
                    operationLogEntity.setCreateTime(createTime);
                    iOperationLogService.save(operationLogEntity);
                }
                break;
                case ERROR: {
                    ErrorLogEntity errorLogEntity = new ErrorLogEntity();
                    errorLogEntity.setTraceId(traceId);
                    errorLogEntity.setUrl(url);
                    errorLogEntity.setRequestParam(params);
                    errorLogEntity.setErrorInfo(exception);
                    errorLogEntity.setIp(ip);
                    errorLogEntity.setLocation(location);
                    errorLogEntity.setIsp(isp);
                    errorLogEntity.setUserAgent(userAgent);
                    errorLogEntity.setOs(os);
                    errorLogEntity.setBrowser(browser);
                    errorLogEntity.setCreateBy(createBy);
                    errorLogEntity.setCreateByName(createByName);
                    errorLogEntity.setCreateTime(createTime);
                    iErrorLogService.save(errorLogEntity);
                }
                break;
                default:
            }

            channel.basicAck(deliveryTag, true);
        } catch (Exception e) {
            log.error(QueueConstant.SYSTEM_LOG_DIRECT_QUEUE, parsedLog);
            log.error(QueueConstant.SYSTEM_LOG_DIRECT_QUEUE, e);
            try {
                channel.basicReject(deliveryTag, false);
            } catch (IOException ioException) {
                log.error(ioException.getMessage());
            }
        }
    }
}
